#include "include.h"

extern uint8_t net_state; /*<! 标识当前网络状态 */
static nvs_handle demoks_ceye_handle;
static const char *TAG = "demoks_ceye";

esp_err_t set_app_url(demoks_ceye_url_t url_type, char *url);
esp_err_t get_app_url(demoks_ceye_url_t url_type, char *url);
esp_err_t set_camera_setup(CAMERA_SETUP_t setup);
esp_err_t get_camera_setup(CAMERA_SETUP_t *setup);

esp_err_t demoks_ceye_write(uint8_t *data, demoks_ceye_size len)
{
    // Write data back to the UART
    uart_write_bytes(UART_NUM_1, (const char *)data, len);
    return ESP_OK;
}

/** 封装数据 */
static esp_err_t demoks_ceye_package(uint8_t cmd, uint8_t *data, demoks_ceye_size len)
{
    if (len + 7 > 65535)
        return ESP_FAIL;
    demoks_ceye_size data_len = len + 7;
    uint8_t *data_tmp = (uint8_t *)malloc(data_len);
    memset(data_tmp, 0, data_len);
    data_tmp[0] = 0x57;
    data_tmp[1] = 0x72;
    data_tmp[2] = cmd;
    data_tmp[3] = NET_TO_LOCK;
    data_tmp[4] = (len & 0xFF00) >> 8;
    data_tmp[5] = (len & 0xFF);
    for (demoks_ceye_size i = 0; i < len; i++)
        data_tmp[6 + i] = data[i];
    size_t check_sum = 0;
    for (demoks_ceye_size i = 0; i < (data_len - 1); i++)
        check_sum += data_tmp[i];
    data_tmp[data_len - 1] = check_sum & 0xFF;
    demoks_ceye_write(data_tmp, data_len);
    return ESP_OK;
}

/**
 * 应答寻找设备
 */
static void ON_CAT_EYE_CMD_DEV_SEEK()
{
    ESP_LOGI(TAG, "ON_CAT_EYE_CMD_DEV_SEEK");
    uint8_t data[1] = {EXECUTE_TRUE};
    ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_DEV_SEEK, &data, 1));
}

/**
 * 应答获取网络状态
 */
static void ON_CAT_EYE_DEV_GET_NET_STATE()
{
    ESP_LOGI(TAG, "ON_CAT_EYE_DEV_GET_NET_STATE");
    uint8_t data[1] = {net_state};
    ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_DEV_GET_NET_STATE, &data, 1));
}

/**
 * 修改 wifi 信息
 */
static void ON_CAT_EYE_CMD_CHANGE_WIFI_INFO(char *json_str)
{
    ESP_LOGI(TAG, "ON_CAT_EYE_CMD_CHANGE_WIFI_INFO %s", json_str);
    cJSON *json, *json_passwd, *json_ssid, *json_auth;
    json = cJSON_Parse(json_str);
    json_passwd = cJSON_GetObjectItem(json, "ps");
    json_ssid = cJSON_GetObjectItem(json, "ssid");
    json_auth = cJSON_GetObjectItem(json, "auth");
    if (!cJSON_IsString(json_passwd) || !cJSON_IsString(json_ssid) || !cJSON_IsNumber(json_auth))
    {
        ESP_LOGW(TAG, "参数错误");
        // 返回失败参数错误!
        uint8_t data[1] = {EXECUTE_FALSE};
        ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_CHANGE_WIFI_INFO, &data, 1));
    }
    else
    {
        ESP_LOGI(TAG, "JSON 解析成功");
        char ssid[32] = {0};
        char passwd[64] = {0};
        wifi_auth_mode_t auth = 0;
        for (size_t i = 0; i < (strlen(json_ssid->valuestring) > sizeof(ssid) ? sizeof(ssid) : strlen(json_ssid->valuestring)); i++)
            ssid[i] = json_ssid->valuestring[i];
        for (size_t i = 0; i < (strlen(json_passwd->valuestring) > sizeof(passwd) ? sizeof(passwd) : strlen(json_passwd->valuestring)); i++)
            passwd[i] = json_passwd->valuestring[i];
        auth = json_auth->valueint & 0xFF;
        set_wifi_info(ssid, passwd, &auth, NULL);
        /*>! 触发密码更新 */
        xEventGroupSetBits(app_event_handle, APP_EVENT_BIT_ON_SET_WIFI_INFO);
        uint8_t data[1] = {EXECUTE_TRUE};
        ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_CHANGE_WIFI_INFO, &data, 1));
    }
    cJSON_Delete(json);
}

/**
 * 修改 url 信息
 */
static void ON_CAT_EYE_CMD_CHANGE_URL(char *json_str)
{
    ESP_LOGI(TAG, "ON_CAT_EYE_CMD_CHANGE_URL %s", json_str);
    cJSON *json, *json_url;
    json = cJSON_Parse(json_str);
    json_url = cJSON_GetObjectItem(json, "url");
    if (!cJSON_IsString(json_url) || (strlen(json_url->valuestring) > URL_LENGTH_MAX))
    {

        ESP_LOGW(TAG, "参数错误,或url长度超过(%d)", URL_LENGTH_MAX);
        // 返回失败参数错误!
        uint8_t data[1] = {EXECUTE_FALSE};
        ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_CHANGE_URL, &data, 1));
    }
    else
    {
        ESP_LOGI(TAG, "JSON 解析成功");
        set_app_url(DEMOKS_CEYE_HTTP_PHOTO_URL, json_url->valuestring);

        char url[URL_LENGTH_MAX] = {0};
        get_app_url(DEMOKS_CEYE_HTTP_PHOTO_URL, &url);
        ESP_LOGI(TAG, "读取URL:%s", url);
        // 验证储存
        ESP_ERROR_CHECK(strcmp(json_url->valuestring, url) == 0 ? ESP_OK : ESP_FAIL);

        uint8_t data[1] = {EXECUTE_TRUE};
        ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_CHANGE_URL, &data, 1));
    }
    cJSON_Delete(json);
}

/**
 * OTA升级
 */
static void ON_CAT_EYE_CMD_OTA(char *json_str)
{
    ESP_LOGI(TAG, "ON_CAT_EYE_CMD_OTA %s", json_str);
    cJSON *json, *json_url;
    json = cJSON_Parse(json_str);
    json_url = cJSON_GetObjectItem(json, "url");
    if (!cJSON_IsString(json_url) || (strlen(json_url->valuestring) > URL_LENGTH_MAX))
    {
        ESP_LOGW(TAG, "参数错误");
        // 返回失败参数错误!
        uint8_t data[1] = {EXECUTE_FALSE};
        ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_CHANGE_URL, &data, 1));
    }
    else
    {
        ESP_LOGI(TAG, "JSON 解析成功");
        set_app_url(DEMOKS_CEYE_HTTP_OTA_URL, json_url->valuestring);

        char url[URL_LENGTH_MAX] = {0};
        get_app_url(DEMOKS_CEYE_HTTP_OTA_URL, &url);
        ESP_LOGI(TAG, "读取URL:%s", url);
        // 验证储存
        ESP_ERROR_CHECK(strcmp(json_url->valuestring, url) == 0 ? ESP_OK : ESP_FAIL);
        uint8_t data[1] = {EXECUTE_TRUE};
        ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_CHANGE_URL, &data, 1));

        if (advanced_https_ota() == ESP_OK)
        {
            /*>! OTA 成功! 返回应答成功后1s重启MCU! */
            ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_CHANGE_URL, &data, 1));
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            esp_restart();
        }
        else
        {
            data[1] = EXECUTE_FALSE;
            ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_CHANGE_URL, &data, 1));
        }
    }
    cJSON_Delete(json);
}

/**
 * 抓拍事件
 */
static void ON_CAT_EYE_CMD_PHOTO_GRAPH(uint8_t dev_id[6], uint8_t time[4])
{
    ESP_LOGI(TAG, "dev_id: %02X %02X %02X %02X %02X %02X",
             dev_id[0],
             dev_id[1],
             dev_id[2],
             dev_id[3],
             dev_id[4],
             dev_id[5]);

    uint32_t timestamp = 0;
    timestamp += time[0] * 0x1000000;
    timestamp += time[1] * 0x10000;
    timestamp += time[2] * 0x100;
    timestamp += time[3] * 0x1;
    ESP_LOGI(TAG, "time: %02X %02X %02X %02X ; timestamp=%d",
             dev_id[0],
             dev_id[1],
             dev_id[2],
             dev_id[3],
             timestamp);
    /*>! 触发抓拍 */
    xEventGroupSetBits(app_event_handle, APP_EVENT_BIT_PHOTOGRAPH);
    /*>! 等待回调 */
    EventBits_t uxBits = xEventGroupWaitBits(app_event_handle,
                                             APP_EVENT_BIT_PHOTOGRAPH_SUCCESS | APP_EVENT_BIT_PHOTOGRAPH_FAIL,
                                             pdTRUE,
                                             pdFALSE,
                                             (portTickType)portMAX_DELAY);
    /*>! 应答MCU */
    uint8_t data[1] = {0};
    data[0] = uxBits & APP_EVENT_BIT_PHOTOGRAPH_SUCCESS ? EXECUTE_TRUE : EXECUTE_FALSE;
    ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_PHOTO_GRAPH, &data, 1));
}

static void ON_CAT_EYE_CMD_CAMERA_SETUP(uint8_t *data)
{
    ESP_LOGI(TAG, "ON_CAT_EYE_CMD_CAMERA_SETUP");
    CAMERA_SETUP_t setup = {0};
    setup.Auto_Exposure = data[0];
    setup.Light_Mode = data[1];
    setup.Color_Saturation = data[2];
    setup.Brightness = data[3];
    setup.Contrast = data[4];
    setup.Special_Effects = data[5];
    setup.Color_Bar = data[6];
    setup.mode = data[7];
    set_camera_setup(setup);

    CAMERA_SETUP_t setup_tmp = {0};
    get_camera_setup(&setup_tmp);

    ESP_LOGI(TAG, "setup_tmp %02X %02X %02X %02X %02X %02X %02X %02X ",
             setup_tmp.Auto_Exposure,
             setup_tmp.Light_Mode,
             setup_tmp.Color_Saturation,
             setup_tmp.Brightness,
             setup_tmp.Contrast,
             setup_tmp.Special_Effects,
             setup_tmp.Color_Bar,
             setup_tmp.mode);

    uint8_t data_a[1] = {EXECUTE_TRUE};
    ESP_ERROR_CHECK(demoks_ceye_package(CAT_EYE_CMD_CAMERA_SETUP, &data_a, 1));
}

esp_err_t demoks_ceye_handle_data(uint8_t *data, demoks_ceye_size len)
{
    const uint8_t cmd = data[2];
    const uint8_t fx = data[3];
    const uint16_t data_len = data[4] * 0x100 + data[5];

    if (fx != LOCK_TO_NET)
        return ESP_FAIL;
    switch (cmd)
    {
    case CAT_EYE_CMD_DEV_SEEK:
    {
        ON_CAT_EYE_CMD_DEV_SEEK();
        break;
    }
    case CAT_EYE_DEV_GET_NET_STATE:
    {
        ON_CAT_EYE_DEV_GET_NET_STATE();
        break;
    }
    case CAT_EYE_CMD_CHANGE_WIFI_INFO:
    {
        char *json_str = (char *)calloc(1, data_len + 1);
        for (size_t i = 0; i < data_len; i++)
            json_str[i] = data[6 + i];

        ON_CAT_EYE_CMD_CHANGE_WIFI_INFO(json_str);
        free(json_str);
        break;
    }
    case CAT_EYE_CMD_CHANGE_URL:
    {
        char *json_str = (char *)calloc(1, data_len + 1);
        for (size_t i = 0; i < data_len; i++)
            json_str[i] = data[6 + i];
        ON_CAT_EYE_CMD_CHANGE_URL(json_str);
        break;
    }
    case CAT_EYE_CMD_PHOTO_GRAPH:
    {
        uint8_t dev_id[6] = {0};
        uint8_t time[4] = {0};
        /**>! 数据从第6位开始 */
        memcpy(dev_id, data + 6, 6);
        memcpy(time, data + 6 + 6, 4);
        ON_CAT_EYE_CMD_PHOTO_GRAPH(dev_id, time);
        break;
    }
    case CAT_EYE_CMD_OTA:
    {
        char *json_str = (char *)calloc(1, data_len + 1);
        for (size_t i = 0; i < data_len; i++)
            json_str[i] = data[6 + i];
        ON_CAT_EYE_CMD_OTA(json_str);
        break;
    }
    case CAT_EYE_CMD_CAMERA_SETUP:
    {
        ON_CAT_EYE_CMD_CAMERA_SETUP(data + 6);
        break;
    }
    default:
        return ESP_FAIL;
    }

    return ESP_OK;
}

esp_err_t get_wifi_info(uint8_t *ssid, uint8_t *passwd, wifi_auth_mode_t *auth, uint8_t *channel)
{
    esp_err_t result = 0;
    uint8_t ssid_tmp[32] = {0};
    uint8_t passwd_tmp[64] = {0};
    /*>! 读取SSID */
    size_t len = sizeof(ssid_tmp);
    result = nvs_get_blob(demoks_ceye_handle, "_ssid", ssid_tmp, &len);
    ESP_LOGI(TAG, "SSID=%.*s;len=%d;", len, ssid_tmp, len);
    if (result != ESP_OK)
        return result;
    else
        for (size_t i = 0; i < len; i++)
            ssid[i] = ssid_tmp[i];

    /*>! 读取鉴权方式 */
    result = nvs_get_u8(demoks_ceye_handle, "_auth", auth);
    if (result != ESP_OK)
        auth[0] = WIFI_AUTH_OPEN; /*>! 设置默认鉴权 */
    len = sizeof(passwd_tmp);
    /*>! 读取密码 */
    if (auth[0] != WIFI_AUTH_OPEN)
    {
        result = nvs_get_blob(demoks_ceye_handle, "_passwd", passwd_tmp, &len);
        ESP_LOGI(TAG, "PASSWD=%.*s;len=%d;", len, passwd_tmp, len);
        if (result != ESP_OK)
        {
            ESP_LOGE(TAG, "This auth is not WIFI_AUTH_OPEN!");
            ESP_LOGE(TAG, "But the password acquisition failed!");
            return result;
        }
        else
            for (size_t i = 0; i < len; i++)
                passwd[i] = passwd_tmp[i];
    }

    /*>! 读取通讯信道 */
    result = nvs_get_u8(demoks_ceye_handle, "_channel", channel);
    if (result != ESP_OK)
        channel[0] = 0; /*>! 设置默认信道 */

    return ESP_OK;
}

esp_err_t set_wifi_info(char ssid[32], char passwd[64], wifi_auth_mode_t *auth, uint8_t *channel)
{
    ESP_LOGI(TAG, "设置WIFI信息到NVS");
    esp_err_t result = 0;
    if (ssid != NULL)
    {
        ESP_LOGI(TAG, "set ssid");
        ESP_ERROR_CHECK(nvs_set_blob(demoks_ceye_handle, "_ssid", ssid, 32));
    }
    if (passwd != NULL)
    {
        ESP_LOGI(TAG, "set passwd");
        ESP_ERROR_CHECK(nvs_set_blob(demoks_ceye_handle, "_passwd", passwd, 64));
    }
    if (auth != NULL)
    {
        ESP_LOGI(TAG, "set auth = %u", auth[0]);
        ESP_ERROR_CHECK(nvs_set_u8(demoks_ceye_handle, "_auth", auth[0]));
    }
    if (channel != NULL)
    {
        ESP_LOGI(TAG, "set channel = %u", channel[0]);
        ESP_ERROR_CHECK(nvs_set_u8(demoks_ceye_handle, "_channel", channel[0]));
    }
    return result;
}

esp_err_t set_app_url(demoks_ceye_url_t url_type, char *url)
{
    if (url_type >= DEMOKS_CEYE_URL_MAX)
        return ESP_FAIL;

    switch (url_type)
    {
    case DEMOKS_CEYE_HTTP_PHOTO_URL:
        ESP_ERROR_CHECK(nvs_set_u16(demoks_ceye_handle, "_url_photo_len", strlen(url)));
        if (strlen(url) > 0)
            ESP_ERROR_CHECK(nvs_set_str(demoks_ceye_handle, "_url_photo", url));
        break;
    case DEMOKS_CEYE_HTTP_OTA_URL:
        ESP_ERROR_CHECK(nvs_set_u16(demoks_ceye_handle, "_url_ota_len", strlen(url)));
        if (strlen(url) > 0)
            ESP_ERROR_CHECK(nvs_set_str(demoks_ceye_handle, "_url_ota", url));
        break;
    default:
        return ESP_FAIL;
    }
    return ESP_OK;
}

esp_err_t get_app_url(demoks_ceye_url_t url_type, char *url)
{
    if (url_type >= DEMOKS_CEYE_URL_MAX)
        return ESP_FAIL;

    switch (url_type)
    {
    case DEMOKS_CEYE_HTTP_PHOTO_URL:
    {
        uint16_t length = 0;
        nvs_get_u16(demoks_ceye_handle, "_url_photo_len", &length);
        if (length > 0)
            nvs_get_str(demoks_ceye_handle, "_url_photo", url, &length);
        else
            return ESP_FAIL;
        break;
    }
    case DEMOKS_CEYE_HTTP_OTA_URL:
    {
        uint16_t length = 0;
        nvs_get_u16(demoks_ceye_handle, "_url_ota_len", &length);
        if (length > 0)
            nvs_get_str(demoks_ceye_handle, "_url_ota", url, &length);
        else
            return ESP_FAIL;
        break;
    }
    default:
        return ESP_FAIL;
    }
    return ESP_OK;
}

esp_err_t set_camera_setup(CAMERA_SETUP_t setup)
{
    ESP_ERROR_CHECK(nvs_set_blob(demoks_ceye_handle, "_cam_setup", &setup, sizeof(CAMERA_SETUP_t)));
    return ESP_OK;
}

esp_err_t get_camera_setup(CAMERA_SETUP_t *setup)
{
    size_t len = sizeof(CAMERA_SETUP_t);
    if (nvs_get_blob(demoks_ceye_handle, "_cam_setup", setup, &len) != ESP_OK)
    {
        CAMERA_SETUP_t _setup = {0};
        _setup.Auto_Exposure = setup->Auto_Exposure = 0x01;
        _setup.Light_Mode = setup->Light_Mode = 0x00;
        _setup.Color_Saturation = setup->Color_Saturation = 0x02;
        _setup.Brightness = setup->Brightness = 0x04;
        _setup.Contrast = setup->Contrast = 0x04;
        _setup.Special_Effects = setup->Special_Effects = 0x00;
        _setup.Color_Bar = setup->Color_Bar = 0x00;
        _setup.mode = setup->mode = 0x00;
        set_camera_setup(_setup);
    }
    return ESP_OK;
}

esp_err_t demoks_ceye_init(void)
{
    esp_err_t result = ESP_FAIL;
    /** 打开nvs */
    ESP_ERROR_CHECK(nvs_open("demoks_ceye", NVS_READWRITE, &demoks_ceye_handle));

    return ESP_OK;
}














esp_err_t set_ota_fig(demoks_ceye_url_t type, lonon_ota_fig_t fig)
{
    switch (type)
    {
    case LONON_OTA_FIG:
        ESP_ERROR_CHECK(nvs_set_u8(demoks_ceye_handle, "_ota_fig", fig));
        break;
    default:
        return ESP_FAIL;
    }
    return ESP_OK;
}

esp_err_t get_ota_fig(demoks_ceye_url_t type, lonon_ota_fig_t *fig)
{
    switch (type)
    {
    case LONON_OTA_FIG:
    {
        return nvs_get_u8(demoks_ceye_handle, "_ota_fig", fig);
    }
    default:
        return ESP_FAIL;
    }
    return ESP_OK;
}







